package Code;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BZRClient {
	
	private Socket socket = null;
	private PrintWriter out = null;
	private BufferedReader in = null;
	private boolean isConnected = false;
	private int port;
	private String host;
	private boolean debug = false;
	
	public BZRClient(String host, int port) {
		this.port = port;
		this.host = host;
		this.connect();
	}
	
	public void connect() {
		if(isConnected) return;
		try {
			socket = new Socket(host, this.port);
			out = new PrintWriter(socket.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
			if(debug) System.out.println(in.readLine());
			setConnected(true);
			out.println("agent 1");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void disconnect() {
		if(!isConnected) return;
		try {
			out.close();
			in.close();
			socket.close();
			setConnected(false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	public synchronized void command(final String command) {
		out.println(command);
	}
	
	public String getResponseLine() {
		try {
			return in.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}
	
	public Map<String, List> getAllTanks() {
		final Map<String, List> map = new HashMap<>();
		final List<Tank> tanks = new ArrayList<>();
		final List<EnemyTank> enemyTanks = new ArrayList<>();
		command("mytanks");
		for(final String[] attrs : getResponseList()) {
			if("mytank".equals(attrs[0])){
				tanks.add(new Tank(attrs));
			} else if("othertank".equals(attrs[0])){
				enemyTanks.add(new EnemyTank(attrs));
			}
		}
		command("othertanks");
		for(final String[] attrs : getResponseList()) {
			if("mytank".equals(attrs[0])){
				tanks.add(new Tank(attrs));
			} else if("othertank".equals(attrs[0])){
				enemyTanks.add(new EnemyTank(attrs));
			}
		}
		map.put("mytanks", tanks);
		map.put("othertanks", enemyTanks);
		return map;
	}
	
	public List<Tank> getTanks() {
		final List<Tank> tanks = new ArrayList<>();
		command("mytanks");
		for(final String[] attrs : getResponseList()) {
			tanks.add(new Tank(attrs));
		}
		
		return tanks;
	}

	public List<EnemyTank> getOtherTanks() {
		final List<EnemyTank> tanks = new ArrayList<>();
		command("othertanks");
			
		for(final String[] attrs : getResponseList()) {
			tanks.add(new EnemyTank(attrs));
		}
		
		return tanks;
	}
	
	public List<Obstacle> getObstacles() {
		final List<Obstacle> obstacles = new ArrayList<>();
		command("obstacles");
		for(final String[] attrs : getResponseList()) {
			obstacles.add(new Obstacle(attrs));
		}
		return obstacles;
	}
	
	public List<Base> getBases() {
		final List<Base> bases = new ArrayList<>();
		command("bases");
		for(final String[] attrs : getResponseList()) {
			bases.add(new Base(attrs));
		}
		return bases;
	}
	
	public Map<String, String> getConstants() {
		final Map<String, String> constants = new HashMap<>();
		command("constants");
		for(final String[] row : getResponseList()) {
			constants.put(row[1], row[2]);
		}
		return constants;
	}
	
	public List<Flag> getFlags() {
		final List<Flag> flags = new ArrayList<>();
		command("flags");
		for(final String[] attrs : getResponseList()) {
			flags.add(new Flag(attrs));
		}
		return flags;
	}
	
	public OccGrid getOccGrid(int tankId) {
		command("occgrid " + tankId);
		List<String[]> list = getResponseList();
		if(list.isEmpty()) {
			return null;
		}
		Point location = new Point(list.get(0)[1]);
		String[] pair = list.get(1)[1].split("x");

		final OccGrid grid = new OccGrid(location, Integer.parseInt(pair[0]), Integer.parseInt(pair[1]), list.subList(2, list.size()));
		return grid;
	}
	
	public synchronized List<String[]> getResponseList() {
		final List<String[]> responseList = new ArrayList<>();
		String responseLine = "";
		while(!responseLine.contains("begin")) {
			responseLine = getResponseLine();
			if(responseLine.contains("fail")) {
				return responseList;
			}
		} 

		responseLine = getResponseLine(); //Skip over "begin"
		while(!responseLine.contains("end")) {
			responseList.add(StringUtils.splitString(responseLine));
			
			responseLine = getResponseLine();
		}
//		for(String[] array: responseList) {
//			for(int i = 0; i < array.length; i++) {
//				System.out.print(array[i] + " ");
//			}
//			System.out.println();
//		}
		return responseList;
	}
	
	public boolean isConnected() {
		return isConnected;
	}

	public void setConnected(boolean isConnected) {
		this.isConnected = isConnected;
	}
	
}
